﻿using System;
using System.Collections.Generic;
using Apache.Cassandra;
using Cassandraemon;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Collections;
using Cassandraemon.Connection;

namespace Cassandraemon.Test
{
	[TestClass]
	public class CassandraConnectionConfigTest
	{
		#region Builder to CassandraConnectionConfig

		[TestMethod]
		public void BuilderTest()
		{
			var hosts = new[] { "a", "b", "c" };
			var builder = new CassandraConnectionConfigBuilder
			{
				Hosts = hosts,
				Port = 9160,
				ConsistencyLevel = ConsistencyLevel.QUORUM,
				Timeout = TimeSpan.FromSeconds(100),
				IsFramed = true,
			};

			// Create config from the builder.

			var config = new CassandraConnectionConfig(builder);
			CollectionAssert.AreEqual(hosts, config.Hosts);
			Assert.AreEqual(9160, config.Port);
			Assert.AreEqual(ConsistencyLevel.QUORUM, config.ConsistencyLevel);
			Assert.AreEqual(TimeSpan.FromSeconds(100), config.Timeout);
			Assert.AreEqual(true, config.IsFramed);
		}

		#endregion

		#region ConnectionString

		[TestMethod]
		public void ConnectionStringTest()
		{
			var hosts = new[] { "a", "b", "c" };
			var builder = new CassandraConnectionConfigBuilder
			{
				Hosts = hosts,
				Port = 9160,
				ConsistencyLevel = ConsistencyLevel.QUORUM,
				IsFramed = true,
			};
			var str = builder.ConnectionString;
			Assert.AreEqual(
				"Hosts=\"a b c\";Port=9160;ConsistencyLevel=QUORUM;IsFramed=True",
				str);

			// Create another builder using its ConnectionString

			var builder2 = new CassandraConnectionConfigBuilder(str);
			CollectionAssert.AreEqual(hosts, builder2.Hosts);
			Assert.AreEqual(9160, builder2.Port);
			Assert.AreEqual(ConsistencyLevel.QUORUM, builder2.ConsistencyLevel);
			Assert.AreEqual(true, builder2.IsFramed);
		}

		#endregion

		#region PoolKeyComparer

		[TestMethod]
		public void PoolKeyComparerHostOrderTest()
		{
			var c1 = new CassandraConnectionConfig("a b c", 9160, "system");
			var c2 = new CassandraConnectionConfig("c a b", 9160, "system");
			var comparer = CassandraConnectionConfig.PoolKeyComparer;
			Assert.AreEqual(comparer.GetHashCode(c1), comparer.GetHashCode(c2));
			Assert.IsTrue(comparer.Equals(c1, c2));
		}

		[TestMethod]
		public void PoolKeyComparerNotEqualTest()
		{
			var c1 = new CassandraConnectionConfig("a b c", 9160, "system");
			var c2 = new CassandraConnectionConfig("a b c", 9160, "test");
			var comparer = CassandraConnectionConfig.PoolKeyComparer;
			Assert.AreNotEqual(comparer.GetHashCode(c1), comparer.GetHashCode(c2));
			Assert.IsFalse(comparer.Equals(c1, c2));
		}

		[TestMethod]
		public void PoolKeyComparerNonPoolKeysTest()
		{
			var c1 = new CassandraConnectionConfig("a b c", 9160, "system");

			// RetryCount is not a poolkey, so changing it should not affect
			// comparison by the PoolKeyComparer.

			var c2 = new CassandraConnectionConfig(c1, new CassandraConnectionConfigBuilder
			{
				RetryCount = 100,
			});
			Assert.AreEqual(100, c2.RetryCount);
			var comparer = CassandraConnectionConfig.PoolKeyComparer;
			Assert.AreEqual(comparer.GetHashCode(c1), comparer.GetHashCode(c2));
			Assert.IsTrue(comparer.Equals(c1, c2));
		}

		#endregion

		#region CreateNodeEnumerator

		[TestMethod]
		public void CreateNodeEnumeratorDefaultTest()
		{
			using (var ctx = CassandraContextTest.CreateContext())
			{
				var config = ctx.ConnectionConfig;
				var e = config.CreateNodeEnumerator(ctx.Pool);
				Assert.IsInstanceOfType(e, typeof(RingNodeEnumerator));
			}
		}

		[TestMethod]
		public void CreateNodeEnumeratorManualTest()
		{
			using (var ctx = CassandraContextTest.CreateContext())
			{
				var config = ctx.ConnectionConfig;
				config = new CassandraConnectionConfig(config, new CassandraConnectionConfigBuilder
				{
					Node = "Manual"
				});
				var e = config.CreateNodeEnumerator(ctx.Pool);
				Assert.IsInstanceOfType(e, typeof(ManualNodeEnumerator));
			}
		}

		[TestMethod]
		public void CreateNodeEnumeratorNamedTest()
		{
			using (var ctx = CassandraContextTest.CreateContext())
			{
				var types = new Type[] {
					typeof(RingNodeEnumerator),
					typeof(ManualNodeEnumerator),
				};
				foreach (var type in types)
				{
					var config = ctx.ConnectionConfig;
					config = new CassandraConnectionConfig(config, new CassandraConnectionConfigBuilder
					{
						Node = type.FullName
					});
					var e = config.CreateNodeEnumerator(ctx.Pool);
					Assert.IsInstanceOfType(e, type);
				}
			}
		}

		#endregion
	}
}
